#include "string.h"
#include "mailbox.h"

#define MAX_NUM_BOX 32

  mailbox_t mboxs[MAX_NUM_BOX];
  mutex_lock_t alloc_lock;

static int mbox_is_full(mailbox_t *mailbox)
{
   
}

static int mbox_is_empty(mailbox_t *mailbox)
{
    
}

static void init_mbox(mailbox_t *mailbox)
{
    
}

void do_mbox_init()
{
  int i = 0;
  do_mutex_lock_acquire(&alloc_lock);
  for(i = 0; i < MAX_NUM_BOX; i++){
    mboxs[i].name[0] = '\0';
    mboxs[i].msg_head = 0;
    mboxs[i].msg_tail = 0;
    mboxs[i].left_space = MAX_MBOX_LENGTH;
    mboxs[i].cited = 0;
  }
  do_mutex_lock_release(&alloc_lock);
}


mailbox_t *do_mbox_open(char *name)
{
  int i = 0;
  do_mutex_lock_acquire(&alloc_lock);
  for(i = 0; i < MAX_NUM_BOX; i++){
    if(!strcmp(mboxs[i].name, name)){
      mboxs->cited++;
      do_mutex_lock_release(&alloc_lock);
      return &mboxs[i];
    }
  }
  for(i = 0; i < MAX_NUM_BOX; i++){
    if(mboxs[i].name[0] == '\0'){
      strcpy(mboxs[i].name, name);
      mboxs[i].cited++;
      do_mutex_lock_release(&alloc_lock);
      return &mboxs[i];
    }
  }
}

void do_mbox_close(mailbox_t *mailbox)
{
  do_mutex_lock_acquire(&alloc_lock);
  if(mailbox->cited == 0){
    mailbox->name[0] = '\0';
    mailbox->msg_head = 0;
    mailbox->msg_tail = 0;
    mailbox->left_space = 0;
    do_condition_init(&mailbox->full);
    do_condition_init(&mailbox->empty);
    do_mutex_lock_init(&mailbox->mutex);
  }
  do_mutex_lock_release(&alloc_lock);
}

void do_mbox_send(mailbox_t *mailbox, void *msg, int msg_length)
{
  do_mutex_lock_acquire(&mailbox->mutex);
  while (mailbox->left_space < msg_length)
  {
    do_condition_wait(&mailbox->mutex, &mailbox->full);
  }
  if(MAX_MBOX_LENGTH - mailbox->msg_tail < msg_length){
    memcpy((uint8_t *)(mailbox->msg + mailbox->msg_tail), (uint8_t *)msg, MAX_MBOX_LENGTH - mailbox->msg_tail);
    mailbox->msg_tail = (mailbox->msg_tail + msg_length) % MAX_MBOX_LENGTH;
    memcpy((uint8_t *)mailbox->msg, (uint8_t *)(msg + msg_length - mailbox->msg_tail), mailbox->msg_tail);
  }
  else
  {
    memcpy((uint8_t *)(mailbox->msg + mailbox->msg_tail), (uint8_t *)msg, msg_length);
    mailbox->msg_tail += msg_length;
  }
  mailbox->left_space -= msg_length;
  do_condition_broadcast(&mailbox->empty);
  do_mutex_lock_release(&mailbox->mutex);
    
}

void do_mbox_recv(mailbox_t *mailbox, void *msg, int msg_length)
{
  do_mutex_lock_acquire(&mailbox->mutex);
  while (MAX_MBOX_LENGTH - mailbox->left_space < msg_length)
  {
    do_condition_wait(&mailbox->mutex, &mailbox->empty);
  }
  if(MAX_MBOX_LENGTH - mailbox->msg_head < msg_length){
    memcpy((uint8_t *)msg, (uint8_t *)(mailbox->msg + mailbox->msg_head), MAX_MBOX_LENGTH - mailbox->msg_head);
    mailbox->msg_head = (mailbox->msg_head + msg_length) % MAX_MBOX_LENGTH;
    memcpy((uint8_t *)(msg + msg_length - mailbox->msg_head), (uint8_t *)(mailbox->msg), mailbox->msg_head);
  }
  else
  {
    memcpy((uint8_t *)msg, (uint8_t *)(mailbox->msg + mailbox->msg_head), msg_length);
    mailbox->msg_head += msg_length;
  }
  mailbox->left_space += msg_length;
  do_condition_broadcast(&mailbox->full);
  do_mutex_lock_release(&mailbox->mutex);
}